<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>五子棋 AI 对战</title>
  <style>
    html, body{
      height: 100%;
      background-image: url(./image/game_background.png);
      background-position: center;
      background-repeat: no-repeat;
    }
    .nav {
      font-size: 24px;
      text-align: center;
      padding: 10px;
      background-color: #f0f0f0;
    }
    .container {
      display: flex;
      justify-content: center;
      margin-top: 20px;
    }
    #screen{
      width: 450px;
      height: 50px;
      margin-top: 10px;
      background-color: #fff;
      font-size: 22px;
      line-height: 50px;
      text-align: center;
    }
  </style>
</head>
<body>
<div class="nav">五子棋在线对战</div>
<div class="container">
  <div>
    <canvas id="chess" width="450" height="450"></canvas>
    <div id="screen"> 等待玩家落子...</div>
  </div>
</div>
<script>
  const BOARD_SIZE = 15;
  const CELL_SIZE = 30;
  let board = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0));
  let currentPlayer = 1; // 1 代表玩家（黑子），2 代表 AI（白子）
  let { chess, context } = initChessBoard('#chess');


  // 初始化棋盘
  function initChessBoard(canvasId) {
    let chess = document.querySelector(canvasId);
    let context = chess.getContext('2d');
    context.strokeStyle = "#BFBFBF";

    // 背景图片
    let logo = new Image();
    logo.src = "image/gobang_background.png";
    logo.onload = function () {
      context.drawImage(logo, 0, 0, 450, 450);
      drawGrid(context);
    }

    return { chess, context };
  }
    // 绘制棋盘网格
    context.strokeStyle = '#ccc';
  function drawGrid(context) {
    for (let i = 0; i < 15; i++) {
      context.moveTo(15 + i * 30, 15);
      context.lineTo(15 + i * 30, 430);
      context.stroke();
      context.moveTo(15, 15 + i * 30);
      context.lineTo(435, 15 + i * 30);
      context.stroke();
    }
    return { chess, context };
  }

  // 绘制一个棋子
  function drawStone(context, i, j, isWhite) {
    context.beginPath();
    context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);
    context.closePath();
    var gradient = context.createRadialGradient(15 + i * 30 + 2, 15 + j * 30 - 2, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);
    if (!isWhite) {
      gradient.addColorStop(0, "#0A0A0A");
      gradient.addColorStop(1, "#636766");
    } else {
      gradient.addColorStop(0, "#D1D1D1");
      gradient.addColorStop(1, "#F9F9F9");
    }
    context.fillStyle = gradient;
    context.fill();
  }


  // 检查是否获胜
  function checkWin(board, row, col, player) {
    const directions = [
      [[1, 0], [-1, 0]], // 水平方向
      [[0, 1], [0, -1]], // 垂直方向
      [[1, 1], [-1, -1]], // 正对角线
      [[1, -1], [-1, 1]] // 反对角线
    ];

    for (const direction of directions) {
      let count = 1;
      for (const [dx, dy] of direction) {
        for (let i = 1; i < 5; i++) {
          const newRow = row + i * dy;
          const newCol = col + i * dx;
          if (newRow >= 0 && newRow < BOARD_SIZE && newCol >= 0 && newCol < BOARD_SIZE && board[newRow][newCol] === player) {
            count++;
          } else {
            break;
          }
        }
      }
      if (count >= 5) {
        return true;
      }
    }
    return false;
  }

  // 重置游戏
  function resetGame() {
    board = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0));
    currentPlayer = 1;
    context.clearRect(0, 0, chess.width, chess.height);
    initChessBoard('#chess');
    document.getElementById('screen').textContent = '等待玩家落子...';
  }

  chess.onclick = function (e) {
    if (currentPlayer === 1) {
      let x = e.offsetX;
      let y = e.offsetY;
      let col = Math.floor(x / CELL_SIZE);
      let row = Math.floor(y / CELL_SIZE);

      if (board[row][col] === 0) {
        drawStone(context, col, row, false);
        board[row][col] = 1;

        if (checkWin(board, row, col, 1)) {
          alert('你赢了！');
          resetGame();
          return;
        }

        currentPlayer = 2;
        document.getElementById('screen').textContent = 'AI 正在思考，请耐心等待...';
        setTimeout(aiMove, 500); // 模拟 AI 思考时间
      }
    }
  }

  // AI 落子
  async function aiMove() {
    const MAX_RETRIES = 5; // 最大重试次数
    let retries = 0;

    while (retries < MAX_RETRIES) {
      const boardText = board.map(row => row.join('')).join('\n');
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 20000); // 设置 20 秒超时时间

      try {
        const response = await fetch('http://8.137.18.32:8081/ai_move', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            board_text: boardText
          }),
          signal: controller.signal
        });

        clearTimeout(timeoutId);

        if (!response.ok) {
          // 处理 HTTP 错误
          const errorText = await response.text();
          throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
        }

        const data = await response.json();
        // 检查返回数据格式是否正确
        if (!data || typeof data.col === 'undefined' || typeof data.row === 'undefined') {
          throw new Error('AI 返回数据格式错误');
        }

        const { row, col } = data;

        if (board[row][col] === 0) {
          drawStone(context, col, row, true);
          board[row][col] = 2;

          if (checkWin(board, row, col, 2)) {
            alert('AI 赢了！');
            resetGame();
            return;
          }

          currentPlayer = 1;
          document.getElementById('screen').textContent = '等待玩家落子...';
          break; // 获得有效落子位置，退出循环
        } else {
          console.log(`AI 给出的位置 (${col}, ${row}) 已有棋子，第 ${retries + 1} 次重试`);
          retries++;
        }
      } catch (error) {
        if (error.name === 'AbortError') {
          console.error('AI 请求超时:', error);
          alert('AI 思考时间过长，请稍等后重试');
        } else {
          console.error('AI 请求出错:', error);
          alert(`AI 请求出错: ${error.message}`);
        }
        currentPlayer = 1;
        document.getElementById('screen').textContent = '等待玩家落子...';
        break;
      }
    }

    if (retries >= MAX_RETRIES) {
      console.error('AI 多次给出无效落子位置，达到最大重试次数');
      alert('AI 多次给出无效落子位置，请重新开始游戏');
      resetGame();
    }
  }
</script>
</body>
</html>